home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / input / input_clock.c next >
C/C++ Source or Header  |  2002-12-12  |  13KB  |  332 lines

  1. /*****************************************************************************
  2.  * input_clock.c: Clock/System date convertions, stream management
  3.  *****************************************************************************
  4.  * Copyright (C) 1999-2001 VideoLAN
  5.  * $Id: input_clock.c,v 1.36 2002/12/12 15:10:58 gbazin Exp $
  6.  *
  7.  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  * 
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23.  
  24. /*****************************************************************************
  25.  * Preamble
  26.  *****************************************************************************/
  27. #include <string.h>                                    /* memcpy(), memset() */
  28.  
  29. #include <vlc/vlc.h>
  30.  
  31. #include "stream_control.h"
  32. #include "input_ext-intf.h"
  33. #include "input_ext-dec.h"
  34. #include "input_ext-plugins.h"
  35.  
  36. /*
  37.  * DISCUSSION : SYNCHRONIZATION METHOD
  38.  *
  39.  * In some cases we can impose the pace of reading (when reading from a
  40.  * file or a pipe), and for the synchronization we simply sleep() until
  41.  * it is time to deliver the packet to the decoders. When reading from
  42.  * the network, we must be read at the same pace as the server writes,
  43.  * otherwise the kernel's buffer will trash packets. The risk is now to
  44.  * overflow the input buffers in case the server goes too fast, that is
  45.  * why we do these calculations :
  46.  *
  47.  * We compute a mean for the pcr because we want to eliminate the
  48.  * network jitter and keep the low frequency variations. The mean is
  49.  * in fact a low pass filter and the jitter is a high frequency signal
  50.  * that is why it is eliminated by the filter/average.
  51.  *
  52.  * The low frequency variations enable us to synchronize the client clock
  53.  * with the server clock because they represent the time variation between
  54.  * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
  55.  * the presentation dates for the audio and video frames. With those dates
  56.  * we can decode (or trash) the MPEG2 stream at "exactly" the same rate
  57.  * as it is sent by the server and so we keep the synchronization between
  58.  * the server and the client.
  59.  *
  60.  * It is a very important matter if you want to avoid underflow or overflow
  61.  * in all the FIFOs, but it may be not enough.
  62.  */
  63.  
  64. /*****************************************************************************
  65.  * Constants
  66.  *****************************************************************************/
  67.  
  68. /* Maximum number of samples used to compute the dynamic average value.
  69.  * We use the following formula :
  70.  * new_average = (old_average * c_average + new_sample_value) / (c_average +1)
  71.  */
  72. #define CR_MAX_AVERAGE_COUNTER 40
  73.  
  74. /* Maximum gap allowed between two CRs. */
  75. #define CR_MAX_GAP 1000000
  76.  
  77. /*****************************************************************************
  78.  * ClockToSysdate: converts a movie clock to system date
  79.  *****************************************************************************/
  80. static mtime_t ClockToSysdate( input_thread_t * p_input,
  81.                                pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
  82. {
  83.     mtime_t     i_sysdate = 0;
  84.  
  85.     if( p_pgrm->i_synchro_state == SYNCHRO_OK )
  86.     {
  87.         i_sysdate = (mtime_t)(i_clock - p_pgrm->cr_ref) 
  88.                         * (mtime_t)p_input->stream.control.i_rate
  89.                         * (mtime_t)300;
  90.         i_sysdate /= 27;
  91.         i_sysdate /= 1000;
  92.         i_sysdate += (mtime_t)p_pgrm->sysdate_ref;
  93.     }
  94.  
  95.     return( i_sysdate );
  96. }
  97.  
  98. /*****************************************************************************
  99.  * ClockCurrent: converts current system date to clock units
  100.  *****************************************************************************
  101.  * Caution : the synchro state must be SYNCHRO_OK for this to operate.
  102.  *****************************************************************************/
  103. static mtime_t ClockCurrent( input_thread_t * p_input,
  104.                              pgrm_descriptor_t * p_pgrm )
  105. {
  106.     return( (mdate() - p_pgrm->sysdate_ref) * 27 * DEFAULT_RATE
  107.              / p_input->stream.control.i_rate / 300
  108.              + p_pgrm->cr_ref );
  109. }
  110.  
  111. /*****************************************************************************
  112.  * ClockNewRef: writes a new clock reference
  113.  *****************************************************************************/
  114. static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
  115.                          mtime_t i_clock, mtime_t i_sysdate )
  116. {
  117.     p_pgrm->cr_ref = i_clock;
  118.     /* this is actually a kludge, but it gives better results when scr
  119.     * is zero in DVDs: we are 3-4 ms in advance instead of sometimes
  120.     * 100ms late  */
  121.     p_pgrm->sysdate_ref = ( p_pgrm->last_syscr && !i_clock )
  122.                           ? p_pgrm->last_syscr
  123.                           : i_sysdate ;
  124. }
  125.  
  126. /*****************************************************************************
  127.  * input_ClockInit: reinitializes the clock reference after a stream
  128.  *                  discontinuity
  129.  *****************************************************************************/
  130. void input_ClockInit( pgrm_descriptor_t * p_pgrm )
  131. {
  132.     p_pgrm->last_cr = 0;
  133.     p_pgrm->last_syscr = 0;
  134.     p_pgrm->cr_ref = 0;
  135.     p_pgrm->sysdate_ref = 0;
  136.     p_pgrm->delta_cr = 0;
  137.     p_pgrm->c_average_count = 0;
  138. }
  139.  
  140. /*****************************************************************************
  141.  * input_ClockManageControl: handles the messages from the interface
  142.  *****************************************************************************
  143.  * Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
  144.  *****************************************************************************/
  145. int input_ClockManageControl( input_thread_t * p_input,
  146.                                pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
  147. {
  148.     int i_return_value = UNDEF_S;
  149.  
  150.     vlc_mutex_lock( &p_input->stream.stream_lock );
  151.  
  152.     if( p_input->stream.i_new_status == PAUSE_S )
  153.     {
  154.         int i_old_status;
  155.  
  156.         vlc_mutex_lock( &p_input->stream.control.control_lock );
  157.         i_old_status = p_input->stream.control.i_status;
  158.         p_input->stream.control.i_status = PAUSE_S;
  159.         vlc_mutex_unlock( &p_input->stream.control.control_lock );
  160.  
  161.         vlc_cond_wait( &p_input->stream.stream_wait,
  162.                        &p_input->stream.stream_lock );
  163.         p_pgrm->last_syscr = 0;
  164.         ClockNewRef( p_pgrm, i_clock, mdate() );
  165.  
  166.         if( p_input->stream.i_new_status == PAUSE_S )
  167.         {
  168.             /* PAUSE_S undoes the pause state: Return to old state. */
  169.             vlc_mutex_lock( &p_input->stream.control.control_lock );
  170.             p_input->stream.control.i_status = i_old_status;
  171.             vlc_mutex_unlock( &p_input->stream.control.control_lock );
  172.  
  173.             p_input->stream.i_new_status = UNDEF_S;
  174.             p_input->stream.i_new_rate = UNDEF_S;
  175.         }
  176.  
  177.         /* We handle i_new_status != PAUSE_S below... */
  178.  
  179.         i_return_value = PAUSE_S;
  180.     }
  181.  
  182.     if( p_input->stream.i_new_status != UNDEF_S )
  183.     {
  184.         vlc_mutex_lock( &p_input->stream.control.control_lock );
  185.  
  186.         p_input->stream.control.i_status = p_input->stream.i_new_status;
  187.  
  188.         ClockNewRef( p_pgrm, i_clock,
  189.                      ClockToSysdate( p_input, p_pgrm, i_clock ) );
  190.  
  191.         if( p_input->stream.control.i_status == PLAYING_S )
  192.         {
  193.             p_input->stream.control.i_rate = DEFAULT_RATE;
  194.             p_input->stream.control.b_mute = 0;
  195.         }
  196.         else
  197.         {
  198.             p_input->stream.control.i_rate = p_input->stream.i_new_rate;
  199.             p_input->stream.control.b_mute = 1;
  200.  
  201.             /* Feed the audio decoders with a NULL packet to avoid
  202.              * discontinuities. */
  203.             input_EscapeAudioDiscontinuity( p_input );
  204.         }
  205.  
  206.         p_input->stream.i_new_status = UNDEF_S;
  207.         p_input->stream.i_new_rate = UNDEF_S;
  208.  
  209.         vlc_mutex_unlock( &p_input->stream.control.control_lock );
  210.     }
  211.  
  212.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  213.  
  214.     return( i_return_value );
  215. }
  216.  
  217. /*****************************************************************************
  218.  * input_ClockManageRef: manages a clock reference
  219.  *****************************************************************************/
  220. void input_ClockManageRef( input_thread_t * p_input,
  221.                            pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
  222. {
  223.     /* take selected program if none specified */
  224.     if( !p_pgrm )
  225.     {
  226.         p_pgrm = p_input->stream.p_selected_program;
  227.     }
  228.  
  229.     if( ( p_pgrm->i_synchro_state != SYNCHRO_OK ) || ( i_clock == 0 ) )
  230.     {
  231.         /* Feed synchro with a new reference point. */
  232.         ClockNewRef( p_pgrm, i_clock, mdate() );
  233.         p_pgrm->i_synchro_state = SYNCHRO_OK;
  234.  
  235.         if( p_input->stream.b_pace_control
  236.              && p_input->stream.p_selected_program == p_pgrm )
  237.         {
  238.             p_pgrm->last_cr = i_clock;
  239.             mwait( ClockToSysdate( p_input, p_pgrm, i_clock ) );
  240.         }
  241.         else
  242.         {
  243.             p_pgrm->last_cr = 0;
  244.             p_pgrm->last_syscr = 0;
  245.             p_pgrm->delta_cr = 0;
  246.             p_pgrm->c_average_count = 0;
  247.         }
  248.     }
  249.     else
  250.     {
  251.         if ( p_pgrm->last_cr != 0 &&
  252.                (    (p_pgrm->last_cr - i_clock) > CR_MAX_GAP
  253.                  || (p_pgrm->last_cr - i_clock) < - CR_MAX_GAP ) )
  254.         {
  255.             /* Stream discontinuity, for which we haven't received a
  256.              * warning from the stream control facilities (dd-edited
  257.              * stream ?). */
  258.             msg_Warn( p_input, "clock gap, unexpected stream discontinuity" );
  259.             input_ClockInit( p_pgrm );
  260.             p_pgrm->i_synchro_state = SYNCHRO_START;
  261.             input_EscapeDiscontinuity( p_input );
  262.         }
  263.  
  264.         p_pgrm->last_cr = i_clock;
  265.  
  266.         if( p_input->stream.b_pace_control
  267.              && p_input->stream.p_selected_program == p_pgrm )
  268.         {
  269.             /* We remember the last system date to be able to restart
  270.              * the synchro we statistically better continuity, after 
  271.              * a zero scr */
  272.             p_pgrm->last_syscr = ClockToSysdate( p_input, p_pgrm, i_clock );
  273.             
  274.             /* Wait a while before delivering the packets to the decoder.
  275.              * In case of multiple programs, we arbitrarily follow the
  276.              * clock of the first program. */
  277.             mwait( p_pgrm->last_syscr );
  278.  
  279.             /* Now take into account interface changes. */
  280.             input_ClockManageControl( p_input, p_pgrm, i_clock );
  281.         }
  282.         else
  283.         {
  284.             /* Smooth clock reference variations. */
  285.             mtime_t     i_extrapoled_clock = ClockCurrent( p_input, p_pgrm );
  286.  
  287.             /* Bresenham algorithm to smooth variations. */
  288.             if( p_pgrm->c_average_count == CR_MAX_AVERAGE_COUNTER )
  289.             {
  290.                 p_pgrm->delta_cr = ( p_pgrm->delta_cr
  291.                                         * (CR_MAX_AVERAGE_COUNTER - 1)
  292.                                       + ( i_extrapoled_clock - i_clock ) )
  293.                                     / CR_MAX_AVERAGE_COUNTER;
  294.             }
  295.             else
  296.             {
  297.                 p_pgrm->delta_cr = ( p_pgrm->delta_cr
  298.                                         * p_pgrm->c_average_count
  299.                                       + ( i_extrapoled_clock - i_clock ) )
  300.                                     / (p_pgrm->c_average_count + 1);
  301.                 p_pgrm->c_average_count++;
  302.             }
  303.         }
  304.     }
  305. }
  306.  
  307. /*****************************************************************************
  308.  * input_ClockGetTS: manages a PTS or DTS
  309.  *****************************************************************************/
  310. mtime_t input_ClockGetTS( input_thread_t * p_input,
  311.                           pgrm_descriptor_t * p_pgrm, mtime_t i_ts )
  312. {
  313.     /* take selected program if none specified */
  314.     if( !p_pgrm )
  315.     {
  316.         p_pgrm = p_input->stream.p_selected_program;
  317.     }
  318.  
  319.     if( p_pgrm->i_synchro_state == SYNCHRO_OK )
  320.     {
  321.         return( ClockToSysdate( p_input, p_pgrm, i_ts + p_pgrm->delta_cr )
  322.                  + p_input->i_pts_delay
  323.                  + (p_input->p_vlc->i_desync > 0
  324.                        ? p_input->p_vlc->i_desync : 0) );
  325.     }
  326.     else
  327.     {
  328.         return 0;
  329.     }
  330. }
  331.  
  332.